/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights
 * reserved. <a>http://www.cqcis.com</a>
 */
package com.cqcis.uip.base.framework.adaptor;

import java.util.Iterator;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

import org.osgi.framework.Bundle;
import org.springframework.beans.BeansException;
import org.springframework.osgi.context.DelegatedExecutionOsgiBundleApplicationContext;
import org.springframework.osgi.extender.internal.dependencies.startup.ContextState;
import org.springframework.osgi.extender.internal.dependencies.startup.DependencyServiceManager;
import org.springframework.osgi.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor;
import org.springframework.osgi.extender.internal.dependencies.startup.ServiceDependency;

import com.cqcis.uip.base.framework.core.UnsatisfiedDependenciesDetector;
import com.cqcis.uip.base.framework.core.impl.ServiceStateManage;

/**
 * 增加Spring上下文，服务等待
 * 
 * @author huangmy
 * @date   2008-3-21
 */
public class DependencyWaiterApplicationContextExecutorAdaptor extends DependencyWaiterApplicationContextExecutor implements UnsatisfiedDependenciesDetector {
    private Object monitor = new Object();
    private Timer watchdog; // 执行
    private long timeout; // 超时时间
    private WatchDogTask watchDogTask;
    private ServiceStateManage ssm;
    private Bundle bundle;
    private AtomicInteger syncCounter = new AtomicInteger(0); // 同步计数器, 初始值为0
    private CountDownLatch syncCDL = new CountDownLatch(1);
    
    private class WatchDogTask extends TimerTask {
		public void run() {
			doTimeout();
		}
	}
    
	public DependencyWaiterApplicationContextExecutorAdaptor(
			DelegatedExecutionOsgiBundleApplicationContext delegateContext, boolean syncWait, ServiceStateManage ssm) {
		super(delegateContext, syncWait);
		this.ssm = ssm;
	}

	// 修改原有刷新上下文行为
	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (syncCounter) { // 必须同步
			this.syncCDL = new CountDownLatch(1);
			this.syncCounter.incrementAndGet();
		}
		
		try {			
		    super.refresh();
		} finally {
			this.syncCDL.countDown();
			this.syncCounter.decrementAndGet();
		}
	}
	
	// 同步上下文刷新与关闭操作，如果当前上下文正在刷新，则必须等刷新操作完成后才执行关闭操作, 
	// 以避免OSGi的BundleContext被关闭导致操作步骤絮乱
	@Override
	public void close() {
		try {
			synchronized (syncCounter) {// 必须同步
				if (this.syncCounter.get() > 0) {
					this.syncCDL.await();
				}
			}						
		} catch (InterruptedException e) {			
		}
		super.close();
	}
	
	protected void startWatchDog() {
		synchronized (monitor) {	
			watchDogTask = new WatchDogTask();
			watchdog.schedule(watchDogTask, (timeout + timeout/3) * 1000);
		}
		
		super.startWatchDog();
	}
	
	@Override
	protected void stopWatchDog() {
		synchronized (monitor) {
			if (watchDogTask != null) {
				watchDogTask.cancel();
				watchDogTask = null;
			}
		}
		
		super.stopWatchDog();
	}
	
	@Override
	protected void stageOne() {
		super.stageOne();
	}
	
	@Override
	public void setTimeout(long timeout) {
		this.timeout = timeout;
		super.setTimeout(timeout);
	}
	
	@Override
	public void setWatchdog(Timer watchdog) {
		this.watchdog = watchdog;
		super.setWatchdog(watchdog);
	}	
	
	@Override
	protected DependencyServiceManager createDependencyServiceListener(Runnable task) {
		return new DependencyServiceManagerAdaptor(this, delegateContext, task, ssm);
	}
	
	@SuppressWarnings("unchecked")
	private void doTimeout() {
		Set<ServiceDependency> unsdps = dependencyDetector.getUnsatisfiedDependencies();
		if (unsdps != null) {
			StringBuffer buffer = new StringBuffer();
			buffer.append("Wait dependency timeout. timeout=")
			      .append(this.timeout/1000).append("s").append("\n");
			
			for (Iterator<ServiceDependency> it = unsdps.iterator(); it.hasNext();) {
				ServiceDependency sd = it.next();				
				buffer.append(sd).append("\n");
			}
			
			ssm.updateState(bundle.getBundleId(), ContextState.RESOLVING_DEPENDENCIES, buffer.toString());
		}
	}
	
	@SuppressWarnings("unchecked")
	public Set<ServiceDependency> getUnsatisfied() {		
		return dependencyDetector == null ? null : dependencyDetector.getUnsatisfiedDependencies();
	}
}
